home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / HTMLWriter.java < prev    next >
Text File  |  1998-06-30  |  62KB  |  2,222 lines

  1. /*
  2.  * @(#)HTMLWriter.java    1.31 98/04/12
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text.html;
  21.  
  22. import java.util.*;
  23. import java.io.IOException;
  24. import java.io.OutputStream;
  25. import java.io.Writer;
  26. import java.io.OutputStreamWriter;
  27. import java.awt.Color;
  28. import java.awt.Font;
  29. import java.awt.FontMetrics;
  30.  
  31. import com.sun.java.swing.text.*;
  32.  
  33. // PENDING(prinz) for the next release this class will
  34. // be completely rewritten.  The attribute policy will be
  35. // different enabling a small amount to code to generate
  36. // the output rather than it's current enormous size.
  37. // Additionally, writing styled documents from JTextPane
  38. // will work.  This class will become public after being
  39. // rewritten, to allow subclasses to refine it's behavior.
  40.  
  41. /**
  42.  * Class to output in writing HTML to a writer or output stream.
  43.  * Things that will differ from original source:
  44.  * 1. Writing out "known" attributes.  Any attributes (e.g.,"foo=x"
  45.  *    will not be restored.
  46.  * 2. Will convert chars ______ to &#NNN;.  
  47.  *
  48.  * @author  Jill Nakata
  49.  * @version 1.31 04/12/98
  50.  */
  51. class HTMLWriter {
  52.  
  53.     private Hashtable branchTable;
  54.     private Hashtable leafTable;
  55.     private boolean lowercase = true;
  56.     private boolean indenting = false;
  57.     private boolean writePre = false;
  58.     private int nPrelines = 0;
  59.     private int inFont = 0;
  60.     private static final String GENERIC = "generic";
  61.     private static final String SPACE = " ";
  62.     private static final String EQUAL = "=";
  63.     private static final String QUOTE = "\"";
  64.     private static final String CR = "\n";
  65.   
  66.  
  67.     /**
  68.      * Creates a new HTMLWriter object.
  69.      */
  70.     public HTMLWriter() {
  71.     initializeBranchTable();
  72.     initializeLeafTable();
  73.     }
  74.  
  75.     /**
  76.      * Writes the document to a stream as HTML starting from root.
  77.      *
  78.      * @param os the output stream
  79.      * @param doc the HTML document
  80.      * @exception Exception on any failure
  81.      */
  82.     public void write(OutputStream os, StyledDocument doc) throws Exception {
  83.         OutputStreamWriter osw = new OutputStreamWriter(os);
  84.         write(osw, doc);
  85.         osw.flush();    
  86.     }
  87.  
  88.     /**
  89.      * Writes the document to a writer as HTML starting from root.
  90.      *
  91.      * @param w the writer
  92.      * @param doc the HTML document
  93.      */
  94.     public void write(Writer w, StyledDocument doc) throws IOException {
  95.  
  96.         AbstractDocument.BranchElement root = 
  97.         (AbstractDocument.BranchElement)doc.getDefaultRootElement();
  98.  
  99.         writeStartTag(w, Constants.HTML);
  100.         writeHead(w, root);
  101.  
  102.         // Write BODY contents by walking  the element tree starting from root.
  103.         writeBranch(w, "", root);
  104.  
  105.         writeEndTag(w, Constants.HTML);
  106.         w.flush();
  107.  
  108.     }
  109.  
  110.     /**
  111.      * Adds an attribute translator.
  112.      *
  113.      * @param tag the translator name
  114.      * @param trans the translator
  115.      */
  116.     public void setBranchTranslator(String tag, BranchTranslator trans) {
  117.     branchTable.put(tag, trans);
  118.     }
  119.  
  120.     /**
  121.      * Gets a translator with a given name.
  122.      *
  123.      * @param tag the name
  124.      * @return the translator
  125.      */
  126.     public BranchTranslator getBranchTranslator(String tag) {
  127.     
  128.     BranchTranslator bt = (BranchTranslator)branchTable.get(tag);
  129. HTMLDebug.println("getBranchTranslator for " + tag);
  130.     //
  131.     // If no translator found for this tag,
  132.     // use the generic one.
  133.     //
  134.     if (bt == null)    {
  135.        bt = getBranchTranslator(GENERIC);
  136.        System.out.println("HTMLWriter.getBranchTranslator: " + 
  137.                   "Using genericBranchTranslator for " + tag);
  138.     }
  139.  
  140.     return bt;
  141.     }
  142.  
  143.     /**
  144.      * Removes a translator.
  145.      *
  146.      * @param tag the translator name
  147.      */
  148.     public void removeBranchTranslator(String tag) {
  149.     branchTable.remove(tag);
  150.     }
  151.  
  152.     /**
  153.      * Adds an attribute translator.
  154.      *
  155.      * @param tag the translator name
  156.      * @param trans the translator
  157.      */
  158.     public void setLeafTranslator(String tag, LeafTranslator trans) {
  159.     leafTable.put(tag, trans);
  160.     }
  161.  
  162.     /**
  163.      * Gets a translator with a given name.
  164.      *
  165.      * @param tag the name
  166.      * @return the translator
  167.      */
  168.     public LeafTranslator getLeafTranslator(String tag) {
  169.  
  170.     LeafTranslator lt = (LeafTranslator)leafTable.get(tag);
  171. HTMLDebug.println("getLeafTranslator for " + tag);
  172.     //
  173.     // If no translator found for this tag,
  174.     // use the generic one.
  175.     //
  176.     if (lt == null)    {
  177. HTMLDebug.println("getLeafTranslator generic ");
  178.        lt = getLeafTranslator(AbstractDocument.ContentElementName);
  179.        //System.out.println("HTMLWriter.getLeafTranslator: " + 
  180.                   //"Using contentTranslator for " + tag);
  181.     }
  182.     return lt;
  183.     }
  184.  
  185.     /**
  186.      * Removes a translator.
  187.      *
  188.      * @param tag the translator name
  189.      */
  190.     public void removeLeafTranslator(String tag) {
  191.     leafTable.remove(tag);
  192.     }
  193.  
  194.     // THIS IS BOGUS AND SHOULD BE REMOVED
  195.     static class HTMLDebug {
  196.  
  197.         public static boolean dbg = false;
  198.  
  199.         public static void setDebug(boolean d)
  200.     {
  201.         dbg = d;
  202.     }
  203.  
  204.         public static void println(String str)
  205.     {
  206.         if(dbg)
  207.         System.out.println(str);
  208.     }
  209.  
  210.         public static boolean debugOn()
  211.     {
  212.         return dbg;
  213.     }
  214.  
  215.     }
  216.  
  217.  
  218.     interface BranchTranslator {
  219.     
  220.     /**
  221.      * Translates a branch element for writing.
  222.      *
  223.      * @param w the writer
  224.      * @param e the element
  225.      */
  226.         public void translate(Writer w, Element e);
  227.     }
  228.  
  229.     interface LeafTranslator {
  230.  
  231.     /**
  232.      * Translates an html leaf for writing.
  233.      *
  234.      * @param w the writer
  235.      * @param parent the element's parent
  236.      * @param e the element
  237.      */
  238.         public void translate(Writer w, Element parent, Element e);
  239.     }
  240.    
  241.     /**
  242.      * Branch Translators...
  243.      */
  244.     class GenericBranchTranslator implements BranchTranslator {
  245.  
  246.     public void translate(Writer w, Element e) {
  247.         String tag;
  248.  
  249.         // Write out tag and attributes.
  250.         AttributeSet a = e.getAttributes();
  251.         AttributeSet style = a.getResolveParent();
  252.         String elementName = e.getName();
  253.         if (elementName.equals(AbstractDocument.ParagraphElementName))    {
  254.                 tag = (String)style.getAttribute(AttributeSet.NameAttribute);
  255.                 // Hack: This name may be "ul li p" so just use "p" translator.
  256.                 if (tag.endsWith(" p"))
  257.                     tag = "p";
  258.         }
  259.         else
  260.         tag = elementName;
  261.  
  262.         tag = convertCase(tag);
  263.         write(w, "<" + tag + ">");
  264.         
  265.         }
  266.     }
  267.  
  268.     class HeadTranslator implements BranchTranslator {
  269.     public void translate(Writer w, Element e) {
  270.  
  271.             write(w, "<" + convertCase(Constants.HEAD) + ">\n");
  272.  
  273.         StyledDocument doc = (StyledDocument)e.getDocument();
  274.         //
  275.         // Write Title, if exists.
  276.         //
  277.         String title = (String)doc.getProperty(Document.TitleProperty);
  278.         if (title != null) { 
  279.         if (indenting == true)
  280.               write(w, "  <" + convertCase(Constants.TITLE) + ">" + title + 
  281.             "</" + convertCase(Constants.TITLE) + ">\n");
  282.         else
  283.               write(w, "<" + convertCase(Constants.TITLE) + ">" + title + 
  284.             "</" + convertCase(Constants.TITLE) + ">\n");
  285.         }
  286.         //
  287.         // Write Base Href, if exists.
  288.         //
  289.         String href = (String)doc.getProperty(Constants.BaseHrefProperty);
  290.         if (href != null) { 
  291.             write(w, "  <" + convertCase(Constants.BASE) + " " + convertCase(Constants.HREF) +
  292.              "=\"" +  href + "\">\n");
  293.         }
  294.  
  295.             write(w, "</" + convertCase(Constants.HEAD) + ">\n");
  296.         }
  297.     }
  298.  
  299.     class BodyTranslator implements BranchTranslator {
  300.  
  301.     public void translate(Writer w, Element e) {
  302.  
  303.             // Write out "<body" and attributes.
  304.         write(w, "<" + convertCase(Constants.BODY));
  305.             AttributeSet a = e.getAttributes();
  306.  
  307.             // Write out " text=#ff0000", if defined.
  308.             String value = (String)a.getAttribute(Constants.TEXT);
  309.             if (value != null) {
  310.                 write(w, SPACE + convertCase(Constants.TEXT) + EQUAL);
  311.                 write(w, convertCase(value));
  312.             }
  313.  
  314.             // Write out " background=#ff0000", if defined.
  315.             value = (String)a.getAttribute(Constants.BACKGROUND);
  316.             if (value != null) {
  317.                 write(w, SPACE + convertCase(Constants.BACKGROUND) + EQUAL);
  318.                 write(w, value);
  319.             }
  320.  
  321.             // Write out " bgcolor=#ff0000", if defined.
  322.             value = (String)a.getAttribute(Constants.BGCOLOR);
  323.             if (value != null) {
  324.                 write(w, SPACE + convertCase(Constants.BGCOLOR) + EQUAL);
  325.                 write(w, convertCase(value));
  326.             }
  327.  
  328.             // Write out " link=#ff0000", if defined.
  329.             value = (String)a.getAttribute(Constants.LINK);
  330.             if (value != null) {
  331.                 write(w, SPACE + convertCase(Constants.LINK) + EQUAL);
  332.                 write(w, convertCase(value));
  333.             }
  334.  
  335.             // Write out " VLINK=#ff0000", if defined.
  336.             value = (String)a.getAttribute(Constants.VLINK);
  337.             if (value != null) {
  338.                 write(w, SPACE + convertCase(Constants.VLINK) + EQUAL);
  339.                 write(w, convertCase(value));
  340.             }
  341.  
  342.             // Write out " ALINK=#ff0000", if defined.
  343.             value = (String)a.getAttribute(Constants.ALINK);
  344.             if (value != null) {
  345.                 write(w, SPACE + convertCase(Constants.ALINK) + EQUAL);
  346.                 write(w, convertCase(value));
  347.             }
  348.  
  349.             write(w, ">");
  350.  
  351.         }
  352.     }
  353.  
  354.     class HTranslator implements BranchTranslator {
  355.  
  356.     public void translate(Writer w, Element e) {
  357.  
  358.         // Write out tag and attributes.
  359.         AttributeSet a = e.getAttributes();
  360.         AttributeSet style = a.getResolveParent();
  361.         String htag = (String)style.getAttribute(AttributeSet.NameAttribute);
  362.         // Write out "<h1"
  363.         write(w, "<");
  364.         write(w, convertCase(htag));
  365.  
  366.         // Write out " align=left,center,right", if defined.
  367.         String value = (String)a.getAttribute(Constants.ALIGN);
  368.         if (value != null) {
  369.             write(w, SPACE + convertCase(Constants.ALIGN) + EQUAL);
  370.             write(w, convertCase(value)); 
  371.         }
  372.  
  373.         write(w, ">");
  374.         }
  375.     }
  376.  
  377.     class LiTranslator implements BranchTranslator {
  378.  
  379.     public void translate(Writer w, Element e) {
  380.  
  381.         // Write out tag and attributes.
  382.         AttributeSet a = e.getAttributes();
  383.  
  384.         // Write out "<li"
  385.         write(w, "<");
  386.         write(w, convertCase(Constants.LI));
  387.  
  388.         // Write out " type=A, a, i"
  389.         String value = (String)a.getAttribute(Constants.TYPE);
  390.         if (value != null) {
  391.             write(w, SPACE + convertCase(Constants.TYPE) + EQUAL);
  392.         value = convertCase(value);
  393.             write(w, value); 
  394.         }
  395.  
  396.         // Write out " value=9"
  397.         value = (String)a.getAttribute(Constants.VALUE);
  398.         if (value != null) {
  399.             write(w, SPACE + convertCase(Constants.VALUE));
  400.         value = convertCase(value);
  401.             write(w, value); 
  402.         }
  403.  
  404.         write(w, ">");
  405.  
  406.         }
  407.     }
  408.  
  409.     class PTranslator implements BranchTranslator {
  410.  
  411.     public void translate(Writer w, Element e) {
  412.  
  413.         // Write out tag and attributes.
  414.         AttributeSet a = e.getAttributes();
  415.  
  416.         // Write out "<p"
  417.         write(w, "<");
  418.         write(w, convertCase(Constants.P));
  419.  
  420.         // Write out " align=center,right,left"
  421.         String value = (String)a.getAttribute(Constants.ALIGN);
  422.         if (value != null) {
  423.             write(w, SPACE + convertCase(Constants.ALIGN) + EQUAL);
  424.             write(w, convertCase(value)); 
  425.         }
  426.  
  427.         write(w, ">");
  428.         }
  429.     }
  430.  
  431.     class PreTranslator implements BranchTranslator {
  432.     public void translate(Writer w, Element e) {
  433.         
  434.         AttributeSet a = e.getAttributes();
  435.  
  436.         // Write out "<pre"
  437.         write(w, "<" + convertCase(Constants.PRE));
  438.  
  439.         // Write out " width=xx", if exists.
  440.         String value = (String)a.getAttribute(Constants.WIDTH);
  441.         if (value != null) {
  442.             write(w, SPACE + convertCase(Constants.WIDTH) + EQUAL);
  443.             write(w, convertCase(value)); 
  444.         }
  445.         write(w, ">");
  446.     
  447.         // Get the number of prelines to process for this Pre tag.
  448.         // This is the number of prelines to write out.
  449.           // Subtract the last one as this was the \n that was added
  450.         // and we don't want to process the last \n.
  451.         nPrelines = e.getElementCount();
  452.     
  453.         }
  454.     }
  455.  
  456.     class DlTranslator implements BranchTranslator {
  457.     public void translate(Writer w, Element e) {
  458.         
  459.         AttributeSet a = e.getAttributes();
  460.  
  461.         // Write out "<dl"
  462.         write(w, "<" + convertCase(Constants.DL));
  463.  
  464.         // Write out " compact", if exists.
  465.         String value = (String)a.getAttribute(Constants.COMPACT);
  466.         if (value == Constants.NULL_ATTRIBUTE) {
  467.             write(w, SPACE + convertCase(Constants.COMPACT));
  468.         }
  469.  
  470.         write(w, ">\n");
  471.         }
  472.     }
  473.  
  474.     class DtTranslator implements BranchTranslator {
  475.     public void translate(Writer w, Element e) {
  476.         
  477.         AttributeSet a = e.getAttributes();
  478.  
  479.         // Write out "<dt"
  480.         write(w, "<" + convertCase(Constants.DT) + ">");
  481.         }
  482.     }
  483.  
  484.     class DdTranslator implements BranchTranslator {
  485.     public void translate(Writer w, Element e) {
  486.         
  487.         AttributeSet a = e.getAttributes();
  488.  
  489.         // Write out "<dd>"
  490.         write(w, "<" + convertCase(Constants.DD) + ">");
  491.         }
  492.     }
  493.  
  494.     class PreLineTranslator implements BranchTranslator {
  495.     public void translate(Writer w, Element e) {
  496.         
  497.         // Decrement the number of prelines left to process
  498.         // for this Pre tag.
  499.         nPrelines--;
  500.  
  501.         // Write out first content in pre line only.
  502.         writePre = true;
  503.  
  504.         }
  505.     }
  506.  
  507.     class UlTranslator implements BranchTranslator {
  508.  
  509.     public void translate(Writer w, Element e) {
  510.  
  511.         // Write out tag and attributes.
  512.         AttributeSet a = e.getAttributes();
  513.  
  514.         // Write out "<ul"
  515.         write(w, "<");
  516.         write(w, convertCase(Constants.UL));
  517.  
  518.         // Write out " type=disc, circle, square"
  519.         String value = (String)a.getAttribute(Constants.TYPE);
  520.         if (value != null) {
  521.             write(w, SPACE + convertCase(Constants.TYPE) + EQUAL);
  522.             write(w, convertCase(value)); 
  523.         }
  524.  
  525.         // Write out " compact"
  526.         value = (String)a.getAttribute(Constants.COMPACT);
  527.         if (value == Constants.NULL_ATTRIBUTE) {
  528.             write(w, SPACE + convertCase(Constants.COMPACT));
  529.         }
  530.  
  531.         write(w, ">\n");
  532.         }
  533.     }
  534.  
  535.     class OlTranslator implements BranchTranslator {
  536.  
  537.     public void translate(Writer w, Element e) {
  538.  
  539.         // Write out tag and attributes.
  540.         AttributeSet a = e.getAttributes();
  541.  
  542.         // Write out "<ol"
  543.         write(w, "<");
  544.         write(w, convertCase(Constants.OL));
  545.  
  546.         // Write out " start=3"
  547.         String value = (String)a.getAttribute(Constants.START);
  548.         if (value != null) {
  549.             write(w, SPACE + convertCase(Constants.START) + EQUAL);
  550.             write(w, convertCase(value)); 
  551.         }
  552.  
  553.         // Write out " type="i""
  554.         value = (String)a.getAttribute(Constants.TYPE);
  555.         if (value != null) {
  556.             write(w, SPACE + convertCase(Constants.TYPE) + EQUAL);
  557.             write(w, QUOTE + convertCase(value) + QUOTE); 
  558.         }
  559.  
  560.         // Write out " compact"
  561.         value = (String)a.getAttribute(Constants.COMPACT);
  562.         if (value == Constants.NULL_ATTRIBUTE) {
  563.             write(w, SPACE + convertCase(Constants.COMPACT));
  564.         }
  565.  
  566.         write(w, ">\n");
  567.         }
  568.     }
  569.  
  570.     class MenuTranslator implements BranchTranslator {
  571.  
  572.     public void translate(Writer w, Element e) {
  573.  
  574.         // Write out tag and attributes.
  575.         AttributeSet a = e.getAttributes();
  576.  
  577.         // Write out "<menu"
  578.         write(w, "<");
  579.         write(w, convertCase(Constants.MENU));
  580.  
  581.         // Write out " type=disc, circle, square"
  582.         String value = (String)a.getAttribute(Constants.TYPE);
  583.         if (value != null) {
  584.             write(w, SPACE + convertCase(Constants.TYPE) + EQUAL);
  585.             write(w, convertCase(value)); 
  586.         }
  587.  
  588.         write(w, ">\n");
  589.         }
  590.     }
  591.  
  592.     class BlockquoteTranslator implements BranchTranslator {
  593.  
  594.     public void translate(Writer w, Element e) {
  595.  
  596.         // Write out tag and attributes.
  597.         AttributeSet a = e.getAttributes();
  598.  
  599.         // Write out "<blockquote"
  600.         write(w, "<");
  601.         write(w, convertCase(Constants.BLOCKQUOTE));
  602.         write(w, ">\n");
  603.         }
  604.     }
  605.  
  606.     /**
  607.      * Leaf Translators...
  608.      */
  609.     class GenericLeafTranslator implements LeafTranslator {
  610.  
  611.     public void translate(Writer w, Element parent, Element e) {
  612.         // Write out tag and attributes.
  613.         String tag = e.getName();
  614.         write(w, "<" + convertCase(tag) + ">");
  615.         }
  616.     }
  617.  
  618.     class ContentTranslator implements LeafTranslator {
  619.  
  620.     public void translate(Writer w, Element parent, Element e) {
  621.  
  622.         Stack tagStack = new Stack();
  623.         Vector tagStyles = new Vector();
  624.  
  625.             AttributeSet style = e.getAttributes();
  626.             AttributeSet pattrs = parent.getAttributes();
  627.             AttributeSet pstyle = pattrs.getResolveParent();  // Paragraph
  628.         //
  629.         // First write out any logical style tags.
  630.         //
  631.         Enumeration names = style.getAttributeNames();
  632.         while (names.hasMoreElements()) {
  633.                 Object name = (Object)names.nextElement();
  634.         if (!name.toString().startsWith("$") &&
  635.             style.getAttribute(name).equals("true")) {
  636.                     HTMLDebug.println(name + "=" + style.getAttribute(name));
  637.             //
  638.             // Add the name of this attribute
  639.             //
  640.             tagStack.push(name);
  641.             write(w, "<" + name + ">");
  642.             //
  643.             // Add the style for this tag to the list of styles
  644.             //
  645.                 StyledDocument doc = (StyledDocument)e.getDocument();
  646.                     AttributeSet tagstyle = doc.getStyle(name.toString());
  647.             if (tagstyle != null) 
  648.                 tagStyles.addElement(tagstyle);
  649.         }
  650.             }
  651.  
  652.         // Write out styles differ from the tag styles.
  653.         writeContent(w, tagStyles, e, parent);
  654.  
  655.         while (tagStack.size() != 0) {
  656.         String name = (String)tagStack.peek();
  657.         write(w, "</" + name + ">");
  658.         tagStack.pop();
  659.         }
  660.         }
  661.     }
  662.  
  663.     class ImgTranslator implements LeafTranslator {
  664.  
  665.     public void translate(Writer w, Element parent, Element e) {
  666.  
  667.         // Write out img tag and attributes.
  668.         AttributeSet a = e.getAttributes();
  669.  
  670.         //
  671.         // SRC is required for img so make sure src exists
  672.         // before writing out "<img"
  673.             //
  674.         String value = (String)a.getAttribute(Constants.SRC);
  675.         if (value == null) {
  676.         System.out.println("HTMLWriter.ImgTranslator: No src attribute for img.");
  677.             return;
  678.         }
  679.  
  680.         //
  681.         // Write out "<img src=value"
  682.         //
  683.         write(w, "<" + convertCase(Constants.IMG) + " " + 
  684.           convertCase(Constants.SRC) + "=" + QUOTE + value.toLowerCase() + QUOTE);
  685.  
  686.         //
  687.         // Write out " height=value", if exists.
  688.         //
  689.         value = (String)a.getAttribute(Constants.HEIGHT);
  690.          if (value != null) {
  691.         write(w, SPACE + convertCase(Constants.HEIGHT) + EQUAL + convertCase(value));
  692.         }
  693.         
  694.         //
  695.         // Write out " width=value", if exists.
  696.         //
  697.         value = (String)a.getAttribute(Constants.WIDTH);
  698.          if (value != null) {
  699.         write(w, SPACE + convertCase(Constants.WIDTH) + EQUAL + convertCase(value));
  700.         }
  701.         
  702.         //
  703.         // Write out " align=value", if exists.
  704.         //
  705.         value = (String)a.getAttribute(Constants.ALIGN);
  706.          if (value != null) {
  707.         write(w, SPACE + convertCase(Constants.ALIGN) + EQUAL + convertCase(value));
  708.         }
  709.         
  710.         //
  711.         // Write out " hspace=value", if exists.
  712.         //
  713.         value = (String)a.getAttribute(Constants.HSPACE);
  714.          if (value != null) {
  715.         write(w, SPACE + convertCase(Constants.HSPACE) + EQUAL + value);
  716.         }
  717.         
  718.         //
  719.         // Write out " vspace=value", if exists.
  720.         //
  721.         value = (String)a.getAttribute(Constants.VSPACE);
  722.          if (value != null) {
  723.         write(w, SPACE + convertCase(Constants.VSPACE) + EQUAL + value);
  724.         }
  725.         
  726.         //
  727.         //
  728.         // Write out " alt=value", if exists.
  729.         //
  730.         value = (String)a.getAttribute(Constants.ALT);
  731.          if (value != null) {
  732.         write(w, SPACE + convertCase(Constants.ALT) + EQUAL + QUOTE + value + QUOTE);
  733.         }
  734.  
  735.         //
  736.         // Write out " border=value", if exists.
  737.         //
  738.         value = (String)a.getAttribute(Constants.BORDER);
  739.          if (value != null) {
  740.         write(w, SPACE + convertCase(Constants.BORDER) + EQUAL + value);
  741.         }
  742.  
  743.         //
  744.         // Write out " usemap", if set.
  745.         //
  746.         value = (String)a.getAttribute(Constants.USEMAP);
  747.          if (value != null) {
  748.         write(w, SPACE + convertCase(Constants.USEMAP));
  749.         }
  750.  
  751.         //
  752.         // Write out " ismap", if set.
  753.         //
  754.         value = (String)a.getAttribute(Constants.ISMAP);
  755.          if (value != null) {
  756.         write(w, SPACE + convertCase(Constants.ISMAP));
  757.         }
  758.         //
  759.         // Close off img tag.
  760.         //
  761.         write(w, ">");
  762.         }
  763.     }
  764.  
  765.     class FontTranslator implements LeafTranslator {
  766.  
  767.     public void translate(Writer w, Element parent, Element e) {
  768.  
  769.             AttributeSet style = e.getAttributes();
  770.             AttributeSet pattrs = parent.getAttributes();
  771.             AttributeSet pstyle = pattrs.getResolveParent();  // Paragraph
  772.  
  773.         // Write "<font"
  774.             if (style.isDefined(StyleConstants.Foreground) ||
  775.                   style.isDefined(StyleConstants.FontSize) ||
  776.                   style.isDefined(StyleConstants.FontFamily)) {
  777.                 inFont++;
  778.                 write(w, "<" + convertCase(Constants.FONT));
  779.             }
  780.  
  781.             // Write " color=red"
  782.             if (style.isDefined(StyleConstants.Foreground)) {
  783.                 Color fg = StyleConstants.getForeground(style);
  784.                 try {
  785.                       String hexstr = Utilities.colorToHex(fg);
  786.                     write(w, " " + convertCase(Constants.COLOR) + "=" + convertCase(hexstr));
  787.                 } catch (Throwable ex) {
  788.                       HTMLDebug.println("Unable to convert Color string:" + fg);
  789.                 }
  790.             }
  791.   
  792.  
  793.             //
  794.             // Write " size=+n"
  795.             //
  796.             if (style.isDefined(StyleConstants.FontSize)) {
  797.                   StyleSheet ss = StyleReader.getStyleSheet();
  798.  
  799.             int ptSize = StyleConstants.getFontSize(style);
  800.             // Convert pt size to a relative value before appending.
  801.             int relSize = ss.getRelSize(ptSize);
  802.             if (relSize < 0)
  803.                 write(w, " " + convertCase(Constants.SIZE) + "=" + relSize);
  804.             else
  805.                 write(w, " " + convertCase(Constants.SIZE) + "=+" + relSize);
  806.         }
  807.  
  808.             // Write " face=times"
  809.             // Fix later, this attribute should go away, not 3.2!
  810.             if (!pstyle.isDefined(StyleConstants.FontFamily) && 
  811.             style.isDefined(StyleConstants.FontFamily)) {
  812.  
  813.             String font = StyleConstants.getFontFamily(style);
  814.             write(w, " " + convertCase(Constants.FACE) + "=\"" + font + "\"");
  815.             }
  816.  
  817.             // Close off <font, if we wrote attributes for this content.
  818.             if (inFont > 0) {
  819.             write(w, ">");
  820.             }
  821.   
  822.     }
  823.  
  824.     }
  825.  
  826.     class HrTranslator implements LeafTranslator {
  827.  
  828.     public void translate(Writer w, Element parent, Element e) {
  829.  
  830.         // Write out tag and attributes.
  831.             AttributeSet a = e.getAttributes();
  832.  
  833.         // Write out "<hr"
  834.         write(w, "<");
  835.         write(w, convertCase(Constants.HR));
  836.  
  837.         // Write out " align=left,center,right"
  838.         String value = (String)a.getAttribute(Constants.ALIGN);
  839.         if (value != null) {
  840.             write(w, SPACE + convertCase(Constants.ALIGN) + EQUAL);
  841.             write(w, convertCase(value)); 
  842.         }
  843.  
  844.         // Write out " noshade"
  845.         value = (String)a.getAttribute(Constants.NOSHADE);
  846.         if (value != null) {
  847.             write(w, SPACE + convertCase(Constants.NOSHADE));
  848.             write(w, convertCase(value)); 
  849.         }
  850.  
  851.         // Write out " size=12"
  852.         value = (String)a.getAttribute(Constants.SIZE);
  853.         if (value != null) {
  854.             write(w, SPACE + convertCase(Constants.SIZE) + EQUAL);
  855.             write(w, value); 
  856.         }
  857.  
  858.         // Write out " width=5,10%"
  859.         value = (String)a.getAttribute(Constants.WIDTH);
  860.         if (value != null) {
  861.             write(w, SPACE + convertCase(Constants.WIDTH));
  862.             write(w, value); 
  863.         }
  864.  
  865.         write(w, ">\n");
  866.  
  867.         }
  868.     }
  869.  
  870.     class ATranslator implements LeafTranslator {
  871.  
  872.     public void translate(Writer w, Element parent, Element e) {
  873.  
  874.         // Write out tag and attributes 
  875.             AttributeSet a = e.getAttributes();
  876.  
  877.         // Write out "<a"
  878.         write(w, "<");
  879.         write(w, convertCase(Constants.A));
  880.  
  881.         // Write out " href="xxx""
  882.         String value = (String)a.getAttribute(Constants.HREF);
  883.         if (value != null) {
  884.             write(w, SPACE + convertCase(Constants.HREF) + EQUAL);
  885.             write(w, QUOTE + value + QUOTE); 
  886.         }
  887.  
  888.         // Write out " name="xxx""
  889.         value = (String)a.getAttribute(Constants.NAME);
  890.         if (value != null) {
  891.             write(w, SPACE + convertCase(Constants.NAME) + EQUAL);
  892.             write(w, QUOTE + value + QUOTE); 
  893.         }
  894.  
  895.         // Write out " rel=next,prev"
  896.         value = (String)a.getAttribute(Constants.REL);
  897.         if (value != null) {
  898.             write(w, SPACE + convertCase(Constants.REL) + EQUAL);
  899.             write(w, value); 
  900.         }
  901.  
  902.         // Write out " rev=next,prev,..."
  903.         value = (String)a.getAttribute(Constants.REV);
  904.         if (value != null) {
  905.             write(w, SPACE + convertCase(Constants.REV));
  906.             write(w, value); 
  907.         }
  908.  
  909.         // Write out " title="xxx""
  910.         value = (String)a.getAttribute(Constants.TITLE);
  911.         if (value != null) {
  912.             write(w, SPACE + convertCase(Constants.TITLE));
  913.             write(w, QUOTE + value + QUOTE); 
  914.         }
  915.  
  916.         // Write out ">"
  917.         write(w, ">");
  918.  
  919.         StyledDocument doc = (StyledDocument)e.getDocument();
  920.             AttributeSet astyle = doc.getStyle(Constants.A);
  921.  
  922.         // Write out styles differ from the A style.
  923.         // Write out content for A tag
  924.         Vector tagStyles = new Vector();
  925.         if (astyle != null) 
  926.             tagStyles.addElement(astyle);
  927.         writeContent(w, tagStyles, e, parent);
  928.  
  929.         // Close off <a>
  930.         write(w, "</" + convertCase(Constants.A) + ">");
  931.  
  932.         }
  933.     }
  934.  
  935.     class CodeTranslator implements LeafTranslator {
  936.  
  937.     public void translate(Writer w, Element parent, Element e) {
  938.  
  939.         // Write out tag and attributes 
  940.             AttributeSet a = e.getAttributes();
  941.  
  942.         // Write out "<code"
  943.         write(w, "<");
  944.         write(w, convertCase(Constants.CODE));
  945.  
  946.         // Write out ">"
  947.         write(w, ">");
  948.  
  949.         StyledDocument doc = (StyledDocument)e.getDocument();
  950.             AttributeSet astyle = doc.getStyle(Constants.CODE);
  951.  
  952.         // Write out styles differ from the CODE style.
  953.         // Write out content for CODE tag
  954.         Vector tagStyles = new Vector();
  955.         if (astyle != null) 
  956.             tagStyles.addElement(astyle);
  957.         writeContent(w, tagStyles, e, parent);
  958.  
  959.         // Close off <code>
  960.         write(w, "</" + convertCase(Constants.CODE) + ">");
  961.  
  962.  
  963.         }
  964.     }
  965.  
  966.     class EmTranslator implements LeafTranslator {
  967.  
  968.     public void translate(Writer w, Element parent, Element e) {
  969.  
  970.         // Write out tag and attributes 
  971.             AttributeSet a = e.getAttributes();
  972.  
  973.         // Write out "<em"
  974.         write(w, "<");
  975.         write(w, convertCase(Constants.EM));
  976.  
  977.         // Write out ">"
  978.         write(w, ">");
  979.  
  980.         StyledDocument doc = (StyledDocument)e.getDocument();
  981.             AttributeSet astyle = doc.getStyle(Constants.EM);
  982.  
  983.         // Write out styles differ from the EM style.
  984.         // Write out content for EM tag
  985.         Vector tagStyles = new Vector();
  986.         if (astyle != null) 
  987.             tagStyles.addElement(astyle);
  988.         writeContent(w, tagStyles, e, parent);
  989.  
  990.         // Close off <em>
  991.         write(w, "</" + convertCase(Constants.EM) + ">");
  992.  
  993.  
  994.         }
  995.     }
  996.  
  997.     class CiteTranslator implements LeafTranslator {
  998.  
  999.     public void translate(Writer w, Element parent, Element e) {
  1000.  
  1001.         // Write out tag and attributes 
  1002.             AttributeSet a = e.getAttributes();
  1003.  
  1004.         // Write out "<cite"
  1005.         write(w, "<");
  1006.         write(w, convertCase(Constants.CITE));
  1007.  
  1008.         // Write out ">"
  1009.         write(w, ">");
  1010.  
  1011.         StyledDocument doc = (StyledDocument)e.getDocument();
  1012.             AttributeSet astyle = doc.getStyle(Constants.CITE);
  1013.  
  1014.         // Write out styles differ from the CITE style.
  1015.         // Write out content for CITE tag
  1016.         Vector tagStyles = new Vector();
  1017.         if (astyle != null) 
  1018.             tagStyles.addElement(astyle);
  1019.         writeContent(w, tagStyles, e, parent);
  1020.  
  1021.         // Close off <cite>
  1022.         write(w, "</" + convertCase(Constants.CITE) + ">");
  1023.  
  1024.         }
  1025.     }
  1026.  
  1027.     class StrikeTranslator implements LeafTranslator {
  1028.  
  1029.     public void translate(Writer w, Element parent, Element e) {
  1030.  
  1031.         // Write out tag and attributes 
  1032.             AttributeSet a = e.getAttributes();
  1033.  
  1034.         // Write out "<strike"
  1035.         write(w, "<");
  1036.         write(w, convertCase(Constants.STRIKE));
  1037.  
  1038.         // Write out ">"
  1039.         write(w, ">");
  1040.  
  1041.         StyledDocument doc = (StyledDocument)e.getDocument();
  1042.             AttributeSet astyle = doc.getStyle(Constants.STRIKE);
  1043.  
  1044.         // Write out styles differ from the STRIKE style.
  1045.         // Write out content for STRIKE tag
  1046.         Vector tagStyles = new Vector();
  1047.         if (astyle != null) 
  1048.             tagStyles.addElement(astyle);
  1049.         writeContent(w, tagStyles, e, parent);
  1050.  
  1051.         // Close off <strike>
  1052.         write(w, "</" + convertCase(Constants.STRIKE) + ">");
  1053.  
  1054.         }
  1055.     }
  1056.  
  1057.     class SubTranslator implements LeafTranslator {
  1058.  
  1059.     public void translate(Writer w, Element parent, Element e) {
  1060.  
  1061.         // Write out tag and attributes 
  1062.             AttributeSet a = e.getAttributes();
  1063.  
  1064.         // Write out "<sub"
  1065.         write(w, "<");
  1066.         write(w, convertCase(Constants.SUB));
  1067.  
  1068.         // Write out ">"
  1069.         write(w, ">");
  1070.  
  1071.         StyledDocument doc = (StyledDocument)e.getDocument();
  1072.             AttributeSet astyle = doc.getStyle(Constants.SUB);
  1073.  
  1074.         // Write out styles differ from the SUB style.
  1075.         // Write out content for SUB tag
  1076.         Vector tagStyles = new Vector();
  1077.         if (astyle != null) 
  1078.             tagStyles.addElement(astyle);
  1079.         writeContent(w, tagStyles, e, parent);
  1080.  
  1081.         // Close off <sub>
  1082.         write(w, "</" + convertCase(Constants.SUB) + ">");
  1083.  
  1084.         }
  1085.     }
  1086.  
  1087.     class TtTranslator implements LeafTranslator {
  1088.  
  1089.     public void translate(Writer w, Element parent, Element e) {
  1090.  
  1091.         // Write out tag and attributes 
  1092.             AttributeSet a = e.getAttributes();
  1093.  
  1094.         // Write out "<tt"
  1095.         write(w, "<");
  1096.         write(w, convertCase(Constants.TT));
  1097.  
  1098.         // Write out ">"
  1099.         write(w, ">");
  1100.  
  1101.         StyledDocument doc = (StyledDocument)e.getDocument();
  1102.             AttributeSet astyle = doc.getStyle(Constants.TT);
  1103.  
  1104.         // Write out styles differ from the TT style.
  1105.         // Write out content for TT tag
  1106.         Vector tagStyles = new Vector();
  1107.         if (astyle != null) 
  1108.             tagStyles.addElement(astyle);
  1109.         writeContent(w, tagStyles, e, parent);
  1110.  
  1111.         // Close off <tt>
  1112.         write(w, "</" + convertCase(Constants.TT) + ">");
  1113.  
  1114.         }
  1115.     }
  1116.  
  1117.     class SupTranslator implements LeafTranslator {
  1118.  
  1119.     public void translate(Writer w, Element parent, Element e) {
  1120.  
  1121.         // Write out tag and attributes 
  1122.             AttributeSet a = e.getAttributes();
  1123.  
  1124.         // Write out "<sup"
  1125.         write(w, "<");
  1126.         write(w, convertCase(Constants.SUP));
  1127.  
  1128.         // Write out ">"
  1129.         write(w, ">");
  1130.  
  1131.         StyledDocument doc = (StyledDocument)e.getDocument();
  1132.             AttributeSet astyle = doc.getStyle(Constants.SUP);
  1133.  
  1134.         // Write out styles differ from the SUP style.
  1135.         // Write out content for SUP tag
  1136.         Vector tagStyles = new Vector();
  1137.         if (astyle != null) 
  1138.             tagStyles.addElement(astyle);
  1139.         writeContent(w, tagStyles, e, parent);
  1140.  
  1141.         // Close off <sup>
  1142.         write(w, "</" + convertCase(Constants.SUP) + ">");
  1143.  
  1144.         }
  1145.     }
  1146.  
  1147.     class BigTranslator implements LeafTranslator {
  1148.  
  1149.     public void translate(Writer w, Element parent, Element e) {
  1150.  
  1151.         // Write out tag and attributes 
  1152.             AttributeSet a = e.getAttributes();
  1153.  
  1154.         // Write out "<big"
  1155.         write(w, "<");
  1156.         write(w, convertCase(Constants.BIG));
  1157.  
  1158.         // Write out ">"
  1159.         write(w, ">");
  1160.  
  1161.         StyledDocument doc = (StyledDocument)e.getDocument();
  1162.             AttributeSet astyle = doc.getStyle(Constants.BIG);
  1163.  
  1164.         // Write out styles differ from the BIG style.
  1165.         // Write out content for BIG tag
  1166.         Vector tagStyles = new Vector();
  1167.         if (astyle != null) 
  1168.             tagStyles.addElement(astyle);
  1169.         writeContent(w, tagStyles, e, parent);
  1170.  
  1171.         // Close off <big>
  1172.         write(w, "</" + convertCase(Constants.BIG) + ">");
  1173.  
  1174.         }
  1175.     }
  1176.  
  1177.     class SmallTranslator implements LeafTranslator {
  1178.  
  1179.     public void translate(Writer w, Element parent, Element e) {
  1180.  
  1181.         // Write out tag and attributes 
  1182.             AttributeSet a = e.getAttributes();
  1183.  
  1184.         // Write out "<small"
  1185.         write(w, "<");
  1186.         write(w, convertCase(Constants.SMALL));
  1187.  
  1188.         // Write out ">"
  1189.         write(w, ">");
  1190.  
  1191.         StyledDocument doc = (StyledDocument)e.getDocument();
  1192.             AttributeSet astyle = doc.getStyle(Constants.SMALL);
  1193.  
  1194.         // Write out styles differ from the SMALL style.
  1195.         // Write out content for SMALL tag
  1196.         Vector tagStyles = new Vector();
  1197.         if (astyle != null) 
  1198.             tagStyles.addElement(astyle);
  1199.         writeContent(w, tagStyles, e, parent);
  1200.  
  1201.         // Close off <small>
  1202.         write(w, "</" + convertCase(Constants.SMALL) + ">");
  1203.  
  1204.         }
  1205.     }
  1206.  
  1207.     class DfnTranslator implements LeafTranslator {
  1208.  
  1209.     public void translate(Writer w, Element parent, Element e) {
  1210.  
  1211.         // Write out tag and attributes 
  1212.             AttributeSet a = e.getAttributes();
  1213.  
  1214.         // Write out "<dfn"
  1215.         write(w, "<");
  1216.         write(w, convertCase(Constants.DFN));
  1217.  
  1218.         // Write out ">"
  1219.         write(w, ">");
  1220.  
  1221.         StyledDocument doc = (StyledDocument)e.getDocument();
  1222.             AttributeSet astyle = doc.getStyle(Constants.DFN);
  1223.  
  1224.         // Write out styles differ from the DFN style.
  1225.         // Write out content for DFN tag
  1226.         Vector tagStyles = new Vector();
  1227.         if (astyle != null) 
  1228.             tagStyles.addElement(astyle);
  1229.         writeContent(w, tagStyles, e, parent);
  1230.  
  1231.         // Close off <dfn>
  1232.         write(w, "</" + convertCase(Constants.DFN) + ">");
  1233.  
  1234.         }
  1235.     }
  1236.  
  1237.     class KbdTranslator implements LeafTranslator {
  1238.  
  1239.     public void translate(Writer w, Element parent, Element e) {
  1240.  
  1241.         // Write out tag and attributes 
  1242.             AttributeSet a = e.getAttributes();
  1243.  
  1244.         // Write out "<kbd"
  1245.         write(w, "<");
  1246.         write(w, convertCase(Constants.KBD));
  1247.  
  1248.         // Write out ">"
  1249.         write(w, ">");
  1250.  
  1251.         StyledDocument doc = (StyledDocument)e.getDocument();
  1252.             AttributeSet astyle = doc.getStyle(Constants.KBD);
  1253.  
  1254.         // Write out styles differ from the KBD style.
  1255.         // Write out content for KBD tag
  1256.         Vector tagStyles = new Vector();
  1257.         if (astyle != null) 
  1258.             tagStyles.addElement(astyle);
  1259.         writeContent(w, tagStyles, e, parent);
  1260.  
  1261.         // Close off <kbd>
  1262.         write(w, "</" + convertCase(Constants.KBD) + ">");
  1263.  
  1264.         }
  1265.     }
  1266.  
  1267.     class SampTranslator implements LeafTranslator {
  1268.  
  1269.     public void translate(Writer w, Element parent, Element e) {
  1270.  
  1271.         // Write out tag and attributes 
  1272.             AttributeSet a = e.getAttributes();
  1273.  
  1274.         // Write out "<samp"
  1275.         write(w, "<");
  1276.         write(w, convertCase(Constants.SAMP));
  1277.  
  1278.         // Write out ">"
  1279.         write(w, ">");
  1280.  
  1281.         StyledDocument doc = (StyledDocument)e.getDocument();
  1282.             AttributeSet astyle = doc.getStyle(Constants.SAMP);
  1283.  
  1284.         // Write out styles differ from the SAMP style.
  1285.         // Write out content for SAMP tag
  1286.         Vector tagStyles = new Vector();
  1287.         if (astyle != null) 
  1288.             tagStyles.addElement(astyle);
  1289.         writeContent(w, tagStyles, e, parent);
  1290.  
  1291.         // Close off <samp>
  1292.         write(w, "</" + convertCase(Constants.SAMP) + ">");
  1293.  
  1294.         }
  1295.     }
  1296.  
  1297.     class StrongTranslator implements LeafTranslator {
  1298.  
  1299.     public void translate(Writer w, Element parent, Element e) {
  1300.  
  1301.         // Write out tag and attributes 
  1302.             AttributeSet a = e.getAttributes();
  1303.  
  1304.         // Write out "<strong"
  1305.         write(w, "<");
  1306.         write(w, convertCase(Constants.STRONG));
  1307.  
  1308.         // Write out ">"
  1309.         write(w, ">");
  1310.  
  1311.         StyledDocument doc = (StyledDocument)e.getDocument();
  1312.             AttributeSet astyle = doc.getStyle(Constants.STRONG);
  1313.  
  1314.         // Write out styles differ from the STRONG style.
  1315.         // Write out content for STRONG tag
  1316.         Vector tagStyles = new Vector();
  1317.         if (astyle != null) 
  1318.             tagStyles.addElement(astyle);
  1319.         writeContent(w, tagStyles, e, parent);
  1320.  
  1321.         // Close off <strong>
  1322.         write(w, "</" + convertCase(Constants.STRONG) + ">");
  1323.  
  1324.         }
  1325.     }
  1326.  
  1327.     class VarTranslator implements LeafTranslator {
  1328.  
  1329.     public void translate(Writer w, Element parent, Element e) {
  1330.  
  1331.         // Write out tag and attributes 
  1332.             AttributeSet a = e.getAttributes();
  1333.  
  1334.         // Write out "<var"
  1335.         write(w, "<");
  1336.         write(w, convertCase(Constants.VAR));
  1337.  
  1338.         // Write out ">"
  1339.         write(w, ">");
  1340.  
  1341.         StyledDocument doc = (StyledDocument)e.getDocument();
  1342.             AttributeSet astyle = doc.getStyle(Constants.VAR);
  1343.  
  1344.         // Write out styles differ from the VAR style.
  1345.         // Write out content for VAR tag
  1346.         Vector tagStyles = new Vector();
  1347.         if (astyle != null) 
  1348.             tagStyles.addElement(astyle);
  1349.         writeContent(w, tagStyles, e, parent);
  1350.  
  1351.         // Close off <var>
  1352.         write(w, "</" + convertCase(Constants.VAR) + ">");
  1353.  
  1354.         }
  1355.     }
  1356.  
  1357.     class PreLeafTranslator implements LeafTranslator {
  1358.  
  1359.     public void translate(Writer w, Element parent, Element e) {
  1360.  
  1361.         StyledDocument doc = (StyledDocument)e.getDocument();
  1362.             AttributeSet prestyle = doc.getStyle(Constants.PRE);
  1363.  
  1364.         // Write out styles that differ from PRE style only.
  1365.         // then write out the actual text.
  1366.         Vector tagStyles = new Vector();
  1367.         if (prestyle != null) 
  1368.             tagStyles.addElement(prestyle);
  1369.         writeContent(w, tagStyles, e, parent);
  1370.         }
  1371.     }
  1372.  
  1373.     class BaseFontTranslator implements LeafTranslator {
  1374.  
  1375.     public void translate(Writer w, Element parent, Element e) {
  1376.  
  1377.         // Write out tag and attributes.
  1378.             AttributeSet a = e.getAttributes();
  1379.  
  1380.         // Write out "<basefont"
  1381.         write(w, "<");
  1382.         write(w, convertCase(Constants.BASEFONT));
  1383.  
  1384.         // Write out " size=1"
  1385.         String value = (String)a.getAttribute(Constants.SIZE);
  1386.         if (value != null) {
  1387.             write(w, SPACE + convertCase(Constants.SIZE) + EQUAL);
  1388.             write(w, value); 
  1389.         }
  1390.  
  1391.         write(w, ">");
  1392.         }
  1393.     }
  1394.  
  1395.     /**
  1396.      * Initialize branch table translators.
  1397.      */
  1398.     private void initializeBranchTable() {
  1399.         branchTable = new Hashtable();
  1400.     setBranchTranslator(GENERIC, new GenericBranchTranslator());
  1401.     setBranchTranslator(Constants.BLOCKQUOTE, new BlockquoteTranslator());
  1402.     setBranchTranslator(Constants.BODY, new BodyTranslator());
  1403.     setBranchTranslator(Constants.DD, new DdTranslator());
  1404.     setBranchTranslator(Constants.DL, new DlTranslator());
  1405.     setBranchTranslator(Constants.DT, new DtTranslator());
  1406.     setBranchTranslator(Constants.HEAD, new HeadTranslator());
  1407.     setBranchTranslator(Constants.H1, new HTranslator());
  1408.     setBranchTranslator(Constants.H2, new HTranslator());
  1409.     setBranchTranslator(Constants.H3, new HTranslator());
  1410.     setBranchTranslator(Constants.H4, new HTranslator());
  1411.     setBranchTranslator(Constants.H5, new HTranslator());
  1412.     setBranchTranslator(Constants.H6, new HTranslator());
  1413.     setBranchTranslator(Constants.LI, new LiTranslator());
  1414.     setBranchTranslator(Constants.MENU, new MenuTranslator());
  1415.     setBranchTranslator(Constants.OL, new OlTranslator());
  1416.     setBranchTranslator(Constants.P, new PTranslator());
  1417.     setBranchTranslator(Constants.PRE, new PreTranslator());
  1418.     setBranchTranslator(Constants.PRELINE, new PreLineTranslator());
  1419.     setBranchTranslator(Constants.UL, new UlTranslator());
  1420.     // more here
  1421.     }
  1422.  
  1423.     /**
  1424.      * Initialize leaf table translators.
  1425.      */
  1426.     private void initializeLeafTable() {
  1427.         leafTable = new Hashtable();
  1428.     setLeafTranslator(GENERIC, new GenericLeafTranslator());
  1429.     setLeafTranslator(AbstractDocument.ContentElementName, new ContentTranslator());
  1430.     setLeafTranslator(StyleConstants.IconElementName, new ImgTranslator());
  1431.     setLeafTranslator(Constants.IMG, new ImgTranslator());
  1432.     setLeafTranslator(Constants.FONT, new FontTranslator());
  1433.     setLeafTranslator(Constants.HR, new HrTranslator());
  1434.     setLeafTranslator(Constants.BASEFONT, new BaseFontTranslator());
  1435.     setLeafTranslator(Constants.A, new ATranslator());
  1436.     setLeafTranslator(Constants.BIG, new BigTranslator());
  1437.     setLeafTranslator(Constants.SMALL, new SmallTranslator());
  1438.     setLeafTranslator(Constants.CODE, new CodeTranslator());
  1439.     setLeafTranslator(Constants.CITE, new CiteTranslator());
  1440.     setLeafTranslator(Constants.STRIKE, new StrikeTranslator());
  1441.     setLeafTranslator(Constants.SUB, new SubTranslator());
  1442.     setLeafTranslator(Constants.SUP, new SupTranslator());
  1443.     setLeafTranslator(Constants.DFN, new DfnTranslator());
  1444.     setLeafTranslator(Constants.KBD, new KbdTranslator());
  1445.     setLeafTranslator(Constants.SAMP, new SampTranslator());
  1446.     setLeafTranslator(Constants.STRONG, new StrongTranslator());
  1447.     setLeafTranslator(Constants.VAR, new VarTranslator());
  1448.     setLeafTranslator(Constants.EM, new EmTranslator());
  1449.     setLeafTranslator(Constants.PRE, new PreLeafTranslator());
  1450.     setLeafTranslator(Constants.TT, new TtTranslator());
  1451.     // more here
  1452.     }
  1453.  
  1454.     /**
  1455.      * Write the leaf tag.
  1456.      */
  1457.     public void writeLeaf(Writer w, String indent, Element parent, Element e) {
  1458.     String     name = e.getName();
  1459.     LeafTranslator     lt = null;
  1460.  
  1461.     //
  1462.     // If this is "content", then see if there is a more
  1463.     // specific tag translator identified by the HTMLTagAttribute
  1464.     // (e.g., "basefontTranslator", or a "blockQuoteTranslator"), 
  1465.     // otherwise use contentTranslator.
  1466.     //
  1467.     if (name.equals(AbstractDocument.ContentElementName)) {
  1468.         AttributeSet a = e.getAttributes();
  1469.         String tagName = (String)a.getAttribute(Constants.HTMLTagAttribute);
  1470.         //String tagName = "Tim's Doh Boy";
  1471.         String styleName = (String)a.getAttribute(AttributeSet.NameAttribute);
  1472.         String elementName = (String)a.getAttribute(AbstractDocument.ElementNameAttribute);
  1473. HTMLDebug.println("writeLeaf(): tagname = " + tagName + " styleName = " + styleName + " elementName " + elementName);
  1474.         if (tagName != null) 
  1475.         name = tagName;
  1476.         else if (styleName != null)
  1477.         name = styleName;
  1478.         else if (elementName != null && elementName.equals(Constants.PRELINE) && styleName != null)
  1479.         name = styleName;
  1480.         else if (elementName == null && styleName != null)
  1481.         name = styleName;
  1482.         
  1483.         //
  1484.         // For some reason, there is a blank content at the end of each doc.
  1485.         // Need to check for this case.
  1486.         //
  1487.         if (tagName != null || styleName != null || elementName != null)
  1488.             lt = getLeafTranslator(name);
  1489.     }
  1490.     //
  1491.     // Some other leaf, e.g., imgTranslator, hrTranslator,
  1492.     //
  1493.      else {
  1494.         lt = getLeafTranslator(name);
  1495.     }
  1496.  
  1497.     //
  1498.     // HR is a special leaf, so indent like a 
  1499.     // paragraph before writing.
  1500.     //
  1501.     if (name.equals(Constants.HR) && indenting == true) {
  1502.         write(w, indent);
  1503.     }
  1504.  
  1505.     // Run it.
  1506.     if (lt != null)
  1507.             lt.translate(w, parent, e);
  1508.     }
  1509.  
  1510.     /**
  1511.      * Generate tags to output in upper case.
  1512.      */
  1513.     public void setUpperCase() {
  1514.         lowercase = false;
  1515.     }
  1516.  
  1517.     /**
  1518.      * Generate tags to output in lower case (default).
  1519.      */
  1520.     public void setLowerCase() {
  1521.         lowercase = true;
  1522.     }
  1523.  
  1524.     /**
  1525.      * Indent HTML tags.
  1526.      */
  1527.     public void setIndent() {
  1528.     indenting = true;
  1529.     }
  1530.  
  1531.     /**
  1532.      * No indenting of  HTML tags.
  1533.      */
  1534.     public void setNoIndent() {
  1535.     indenting = false;
  1536.     }
  1537.  
  1538.     /**
  1539.      * Walks the element tree and calls writeBranch() or writeLeaf()
  1540.      * not assuming any particular element structure.
  1541.      */
  1542.     public void writeBranch(Writer w, String indent, Element e) {
  1543.  
  1544.     String name;
  1545.  
  1546.     if (e.isLeaf()) {
  1547.         AttributeSet a = e.getAttributes();
  1548.         writeLeaf(w, indent, e.getParentElement(), e);
  1549.     }
  1550.     else {
  1551.         String elementName = e.getName();
  1552.  
  1553.         if (elementName.equals(AbstractDocument.SectionElementName))
  1554.             // Force the body translator for a "section" element.
  1555.             name = Constants.BODY;
  1556.         // Use "p", "h1", "h2" as name to get translator.
  1557.         else if (elementName.equals(AbstractDocument.ParagraphElementName)) {
  1558.             AttributeSet a = e.getAttributes();
  1559.             AttributeSet style = a.getResolveParent();
  1560.             name = (String)style.getAttribute(AttributeSet.NameAttribute);
  1561.         // FXME: This name may be "ul li p" so just use "p" translator.
  1562.         if (name.endsWith(" p"))
  1563.             name = "p";
  1564.         }
  1565.         // Use "ul", "li" as name to get translator.
  1566.         else {
  1567.         name = elementName;
  1568.             }
  1569.  
  1570.         // For some reason, there is an element at the top 
  1571.         // called "default".
  1572.         // Skip it.
  1573.         if (name.equals("default"))
  1574.         name = "p";
  1575.  
  1576.         //
  1577.         // Get impliedp attribute.
  1578.         //
  1579.         AttributeSet attrs = e.getAttributes();
  1580.         String value = (String)attrs.getAttribute(Constants.IMPLIEDP);
  1581.         boolean impliedp = false;
  1582.         if (value != null && value.equals(Constants.IMPLIEDP))
  1583.         impliedp = true;
  1584.  
  1585.         //
  1586.         // If indenting turned on, write out indent for all paragraphs.
  1587.         // except for PRE or impliedp's.
  1588.          //
  1589.         if (indenting == true) {
  1590.         if (!name.equals(Constants.PRELINE) && !impliedp)
  1591.                 write(w, indent);
  1592.         }
  1593.  
  1594.         //
  1595.         // Don't write out any implied p start tags.
  1596.         //
  1597.         if (impliedp == true) {
  1598.          //System.out.println("name has impliedp: " + name);
  1599.         }
  1600.         else {
  1601.                 BranchTranslator bt = getBranchTranslator(name);
  1602.  
  1603.             //
  1604.             // If no indenting, add an extra \n for readability
  1605.         // and if not a PRE.
  1606.             //
  1607.             if (indenting == false && !name.equals(Constants.PRELINE))
  1608.             write(w,"\n");
  1609.   
  1610.                 // Run it.
  1611.                 bt.translate(w, e);
  1612.         }
  1613.  
  1614.         //
  1615.         // Now traverse the children of this branch element
  1616.         //
  1617.         int n = e.getElementCount();
  1618.         for (int i = 0; i < n; i++) {
  1619.             Element elem = e.getElement(i);
  1620.         if (indenting == true)
  1621.                 writeBranch(w, indent + "  ", elem);
  1622.         else
  1623.                 writeBranch(w, "", elem);
  1624.         }
  1625.  
  1626.         //
  1627.         // Don't write out any implied p end tags.
  1628.         //
  1629.         if (value != null && value.equals(Constants.IMPLIEDP))
  1630.             write(w, "");
  1631.         else
  1632.             writeEndTag(w, name, indent);
  1633.     }
  1634.     }
  1635.  
  1636.     /**
  1637.      * Write <HEAD> tag.
  1638.      */
  1639.     public void writeHead(Writer w, Element e) {
  1640.  
  1641.         BranchTranslator bt = getBranchTranslator(Constants.HEAD);
  1642.   
  1643.         // Run it.
  1644.         bt.translate(w, e);
  1645.     
  1646.     }
  1647.  
  1648.     /**
  1649.      * Write a start tag <tag> with a \n.
  1650.      */
  1651.     public void writeStartTag(Writer w, String tag) {
  1652.  
  1653.     if (!lowercase)
  1654.        tag.toUpperCase();
  1655.  
  1656.         write(w, "<" + tag + ">\n");
  1657.     }
  1658.  
  1659.     /**
  1660.      * Write an end tag </tag> with a \n.
  1661.      */
  1662.     public void writeEndTag(Writer w, String tag) {
  1663.  
  1664.     if (!lowercase)
  1665.         tag.toUpperCase();
  1666.  
  1667.         write(w, "</" + tag + ">\n");
  1668.     }
  1669.  
  1670.     /**
  1671.      * Write an end tag </tag> with a \n and indenting.
  1672.      */
  1673.     public void writeEndTag(Writer w, String tag, String indent) {
  1674.  
  1675.     if (!lowercase)
  1676.         tag.toUpperCase();
  1677.  
  1678.     //
  1679.     // No indenting for PRE, P, H end tags.
  1680.     //
  1681.     if (tag.equals(Constants.PRE) ||
  1682.         tag.equals(Constants.P) ||
  1683.         tag.equals(Constants.H1) ||
  1684.         tag.equals(Constants.H2) ||
  1685.         tag.equals(Constants.H3) ||
  1686.         tag.equals(Constants.H4) ||
  1687.         tag.equals(Constants.H5) ||
  1688.         tag.equals(Constants.H6)) {
  1689.             write(w, "</" + tag + ">\n");
  1690.     }
  1691.       
  1692.     //
  1693.     // Just a CR for DT, DD
  1694.     //
  1695.     else if (tag.equals(Constants.DT) ||
  1696.          tag.equals(Constants.LI) ||
  1697.          tag.equals(Constants.DD)) {
  1698.         write(w, CR);
  1699.     }
  1700. /*
  1701.     //
  1702.     // CR after MENU, OL, UL
  1703.     //
  1704.     else if (tag.equals(MENU) ||
  1705.          tag.equals(DL) ||
  1706.          tag.equals(OL) ||
  1707.          tag.equals(UL) {
  1708.         if (indenting == true)
  1709.             write(w, indent + "</" + tag + ">\n");
  1710.         else
  1711.             write(w, "</" + tag + ">\n");
  1712.     }
  1713. */
  1714.     //
  1715.     // Check if an end tag is even required.
  1716.     //
  1717.     else if (!tag.equals(Constants.LI) &&
  1718.         !tag.equals(Constants.DD) &&
  1719.         !tag.equals(Constants.DT) &&
  1720.         !tag.equals(Constants.HR) &&
  1721.         !tag.equals(Constants.PRELINE)) {
  1722.         if (indenting == true)
  1723.                 write(w, indent + "</" + tag + ">\n");
  1724.         else
  1725.                 write(w, "</" + tag + ">\n");
  1726.     }
  1727.     }
  1728.  
  1729.     /**
  1730.      * Write a string out
  1731.      */
  1732.     public void write(Writer w, String str) {
  1733.           HTMLDebug.println("Output=>" + str + "<=");
  1734.           int len = str.length();
  1735.           for (int i = 0; i < len; i++) {
  1736.         try {
  1737.                w.write(str.charAt(i));
  1738.         } catch (IOException e) {
  1739.           System.out.println("HTMLWriter.write: " + str + " " +  e);
  1740.         }
  1741.           }
  1742.     }
  1743.  
  1744.     /**
  1745.      * Converts value to lower case if lowercase flag it set.
  1746.      * otherwiser, converts to upper case.
  1747.      */
  1748.     private String convertCase(String val) {
  1749.     if (lowercase)
  1750.         return val.toLowerCase();
  1751.     else
  1752.         return val.toUpperCase();
  1753.     }
  1754.  
  1755.     /**
  1756.      * Converts an alignment value to string value
  1757.     **/
  1758.     private String toAlignString(int align) {
  1759.  
  1760.         String alignstr = "left";
  1761.  
  1762.         switch (align) {
  1763.             case StyleConstants.ALIGN_LEFT:
  1764.                 alignstr = "left";
  1765.               break;
  1766.             case StyleConstants.ALIGN_RIGHT:
  1767.               alignstr = "right";
  1768.               break;
  1769.             case StyleConstants.ALIGN_CENTER:
  1770.               alignstr = "center";
  1771.               break;
  1772.             /*
  1773.             case StyleConstants.ALIGN_JUSTIFIED:
  1774.               alignstr = "left";
  1775.               break;
  1776.             */
  1777.         }
  1778.  
  1779.         return alignstr;
  1780.     }
  1781.  
  1782.     /**
  1783.      * Compares the content's fg color in style with surround 
  1784.      * styles (tagstyles) or the resolve parent to determine 
  1785.      * if the fg color needs to be written.
  1786.      */
  1787.     private boolean writeColor(AttributeSet pstyle, Vector tagstyles, 
  1788.                 AttributeSet style) {
  1789.  
  1790.         Color fg = StyleConstants.getForeground(style);
  1791.  
  1792.     //
  1793.     // Check if any tag styles defines this fg color.
  1794.     // If so, then no need for a color attribute.
  1795.     // FIX ME to look in correct nested order.
  1796.     // Inner most attributes take precedence.
  1797.     //
  1798.     if (tagstyles != null) {
  1799.         for (int i = 0; i < tagstyles.size(); i ++) {
  1800.         Style tagstyle = (Style)tagstyles.elementAt(i);
  1801.         if (fg == StyleConstants.getForeground(tagstyle))
  1802.             return false;
  1803.         }
  1804.     }
  1805.  
  1806.     //
  1807.     // Check if resolve parent defines this fg color
  1808.     //
  1809.     if (fg == StyleConstants.getForeground(pstyle))
  1810.         return false;
  1811.  
  1812.     return true;
  1813.     }
  1814.  
  1815.     /**
  1816.      * Compares the content's font family in style with surround 
  1817.      * styles (tagstyles) or the resolve parent to determine 
  1818.      * if the fg color needs to be written.
  1819.      */
  1820.     private boolean writeFamily(AttributeSet pstyle, Vector tagstyles, AttributeSet style) {
  1821.  
  1822.     String family = StyleConstants.getFontFamily(style);
  1823.  
  1824.     //
  1825.     // Check if any tag styles define this font family.
  1826.     // If so, then no need for a font face attribute.
  1827.     // FIX ME to look in correct nested order.
  1828.     // Inner most attributes take precedence.
  1829.     //
  1830.     if (tagstyles != null) {
  1831.         for (int i = 0; i < tagstyles.size(); i ++) {
  1832.         Style tagstyle = (Style)tagstyles.elementAt(i);
  1833.         if (family == StyleConstants.getFontFamily(tagstyle))
  1834.             return false;
  1835.         }
  1836.     }
  1837.  
  1838.     //
  1839.     // Check if resolve parent defines this fg color
  1840.     //
  1841.     if (family == StyleConstants.getFontFamily(pstyle))
  1842.         return false;
  1843.  
  1844.     return true;
  1845.     }
  1846.  
  1847.     /**
  1848.      * Compares the content's font size in style with surround 
  1849.      * styles (tagstyles) or the resolve parent to determine 
  1850.      * if the fg color needs to be written.
  1851.      */
  1852.     private boolean writeSize(AttributeSet pstyle, Vector tagstyles, AttributeSet style) {
  1853.  
  1854.     int ptSize = StyleConstants.getFontSize(style);
  1855.  
  1856.     //
  1857.     // Check if any tag styles defines this size.
  1858.     // If so, then no need for a size attribute.
  1859.     // FIX ME to look in correct nested order.
  1860.     // Inner most attributes take precedence.
  1861.     //
  1862.     if (tagstyles != null) {
  1863.         for (int i = 0; i < tagstyles.size(); i ++) {
  1864.         Style tagstyle = (Style)tagstyles.elementAt(i);
  1865.         if (ptSize == StyleConstants.getFontSize(tagstyle))
  1866.             return false;
  1867.         }
  1868.     
  1869.     }
  1870.  
  1871.     //
  1872.     // Check if resolve parent defines this fg color
  1873.     //
  1874.     if (ptSize == StyleConstants.getFontSize(pstyle))
  1875.         return false;
  1876.  
  1877.     return true;
  1878.     }
  1879.  
  1880.     /**
  1881.      * Determines of the <font> tag needs to be written.
  1882.      */
  1883.     private boolean writeFontTag(AttributeSet pstyle, Vector tagstyles, AttributeSet style) {
  1884.     
  1885.     if (writeColor(pstyle, tagstyles, style))
  1886.         return true;
  1887.     
  1888.     if (writeSize(pstyle, tagstyles, style))
  1889.         return true;
  1890.  
  1891.     if (writeFamily(pstyle, tagstyles, style))
  1892.         return true;
  1893.  
  1894.     return false;
  1895.     }
  1896.  
  1897.     /**
  1898.      * Determines if the <b> tag needs to be written by
  1899.      * checking surround tags or resolve parent.
  1900.      */
  1901.     private boolean writeBoldTag(AttributeSet pstyle, Vector tagstyles, 
  1902.                    AttributeSet style) {
  1903.  
  1904.         if (StyleConstants.isBold(style)) {
  1905.  
  1906.         //
  1907.         // Check if any of the surround tags define bold.
  1908.         // If so, then no need to write out a bold tag.
  1909.         //
  1910.         if (tagstyles != null) {
  1911.             for (int i = 0; i < tagstyles.size(); i ++) {
  1912.             Style tagstyle = (Style)tagstyles.elementAt(i);
  1913.             if (StyleConstants.isBold(tagstyle))
  1914.                 return false;
  1915.         }
  1916.         }
  1917.  
  1918.         //
  1919.         // If the resolve parent defines bold then
  1920.         // no need to write out bold tag.
  1921.         //
  1922.         if (StyleConstants.isBold(pstyle))
  1923.             // parent and tag style is not bold so <b> tag is needed
  1924.             return false;
  1925.  
  1926.         return true;
  1927.     }
  1928.     else
  1929.         return false;
  1930.     }
  1931.  
  1932.     /**
  1933.      * Determines if the <i> tag needs to be written by
  1934.      * checking surround tags or resolve parent.
  1935.      */
  1936.     private boolean writeItalicTag(AttributeSet pstyle, Vector tagstyles, 
  1937.                    AttributeSet style) {
  1938.  
  1939.         if (StyleConstants.isItalic(style)) {
  1940.  
  1941.         //
  1942.         // Check if any of the surround tags define bold.
  1943.         // If so, then no need to write out a bold tag.
  1944.         //
  1945.         if (tagstyles != null) {
  1946.             for (int i = 0; i < tagstyles.size(); i ++) {
  1947.             Style tagstyle = (Style)tagstyles.elementAt(i);
  1948.             if (StyleConstants.isItalic(tagstyle))
  1949.                 return false;
  1950.         }
  1951.         }
  1952.  
  1953.         //
  1954.         // If the resolve parent defines italic then
  1955.         // no need to write out italic tag.
  1956.         //
  1957.         if (StyleConstants.isItalic(pstyle))
  1958.             // parent and tag style is not italic so <i> tag is needed
  1959.             return false;
  1960.  
  1961.         return true;
  1962.     }
  1963.     else
  1964.         return false;
  1965.     }
  1966.  
  1967.     /**
  1968.      * Determines if the <u> tag needs to be written by
  1969.      * checking surround tags or resolve parent.
  1970.      */
  1971.     private boolean writeUnderlineTag(AttributeSet pstyle, Vector tagstyles, 
  1972.                       AttributeSet style) {
  1973.  
  1974.         if (StyleConstants.isUnderline(style)) {
  1975.  
  1976.         //
  1977.         // Check if any of the surround tags define underlining.
  1978.         // If so, then no need to write out a underline tag.
  1979.         //
  1980.         if (tagstyles != null) {
  1981.             for (int i = 0; i < tagstyles.size(); i ++) {
  1982.             Style tagstyle = (Style)tagstyles.elementAt(i);
  1983.             if (StyleConstants.isUnderline(tagstyle))
  1984.                 return false;
  1985.         }
  1986.         }
  1987.  
  1988.         //
  1989.         // If the resolve parent defines fold then
  1990.         // no need to write out underlinen tag.
  1991.         //
  1992.         if (StyleConstants.isUnderline(pstyle))
  1993.             // parent and tag style is not underline so <u> tag is needed
  1994.             return false;
  1995.  
  1996.         return true;
  1997.     }
  1998.     else
  1999.         return false;
  2000.     }
  2001.  
  2002.     /**
  2003.      * Checks to see if the char attributes are necessary 
  2004.      * before writing.  The char attribute may already be
  2005.      * set in the parent or in the style for the surrounding
  2006.      * tags (tagstyles).
  2007.      */
  2008.     private void writeContent(Writer w, Vector tagstyles, Element e, Element parent) {
  2009.  
  2010.         AttributeSet style = e.getAttributes();
  2011.         AttributeSet pattrs = parent.getAttributes();
  2012.         AttributeSet pstyle = pattrs.getResolveParent();  // Paragraph
  2013.  
  2014.     //
  2015.     // Sanity check.
  2016.     //
  2017.     //if (tagstyle == null)
  2018.         //tagstyle = pstyle;
  2019.  
  2020.         //
  2021.         // Write out "<b>", "<i>", or"<u>"
  2022.         // If parent is bold, then no need to write
  2023.         // bold for this content.  Same for italic, underline.
  2024.         //
  2025.         String b = "b";
  2026.         String i = "i";
  2027.         String u = "u";
  2028.  
  2029.     //
  2030.     // If the parent's style is not bold          &&
  2031.     //    the style for this tag is not bold     &&
  2032.     //    the style for this content is bold    
  2033.     // then write out a <b>
  2034.     //
  2035.     boolean boldtag = writeBoldTag(pstyle, tagstyles, style);
  2036.         if (boldtag)
  2037.             write(w, "<" + convertCase(b) + ">");
  2038.  
  2039.         boolean italictag = writeItalicTag(pstyle, tagstyles, style);
  2040.         if (italictag)
  2041.             write(w, "<" + convertCase(i) + ">");
  2042.  
  2043.         boolean underlinetag = writeUnderlineTag(pstyle, tagstyles, style);
  2044.         if (underlinetag)
  2045.             write(w, "<" + convertCase(u) + ">");
  2046.  
  2047.     // Write "<font"
  2048.     boolean fonttag = writeFontTag(pstyle, tagstyles, style);
  2049.     if (fonttag) {
  2050.             inFont++;
  2051.             write(w, "<" + convertCase(Constants.FONT));
  2052.         }
  2053.  
  2054.         // Write " color=red"
  2055.     boolean colortag = writeColor(pstyle, tagstyles, style);
  2056.         if (colortag) {
  2057.             Color fg = StyleConstants.getForeground(style);
  2058.             try {
  2059.                    String hexstr = Utilities.colorToHex(fg);
  2060.                  write(w, " " + convertCase(Constants.COLOR) + "=" + convertCase(hexstr));
  2061.             }
  2062.             catch (Throwable ex) {
  2063.                    HTMLDebug.println("Unable to convert Color string:" + fg);
  2064.             }
  2065.         }
  2066.   
  2067.         //
  2068.         // Write " size=+n"
  2069.         //
  2070.     boolean sizetag = writeSize(pstyle, tagstyles, style);
  2071.         if (sizetag) {
  2072.             StyleSheet ss = StyleReader.getStyleSheet();
  2073.  
  2074.         int ptSize = StyleConstants.getFontSize(style);
  2075.         // Convert pt size to a relative value before appending.
  2076.         int relSize = ss.getRelSize(ptSize);
  2077.         if (relSize < 0)
  2078.             write(w, " " + convertCase(Constants.SIZE) + "=" + relSize);
  2079.         else
  2080.             write(w, " " + convertCase(Constants.SIZE) + "=+" + relSize);
  2081.     }
  2082.  
  2083.         // Write " face=times"
  2084.         // Fix later, this attribute should go away, not 3.2!
  2085.     boolean familytag = writeFamily(pstyle, tagstyles, style);
  2086.         if (familytag) {
  2087.         String font = StyleConstants.getFontFamily(style);
  2088.         write(w, " " + convertCase(Constants.FACE) + "=\"" + font + "\"");
  2089.         }
  2090.  
  2091.         // Close off <font, if we wrote attributes for this content.
  2092.         if (fonttag) {
  2093.         write(w, ">");
  2094.         }
  2095.  
  2096.     // Write out the actual content.
  2097.         String name = (String)style.getAttribute(AttributeSet.NameAttribute);
  2098.     if (name.equals(Constants.PRE)) {
  2099.         writePreText(w, e);
  2100.     }
  2101.     else
  2102.         writeText(w, e);
  2103.  
  2104.     // Close off <FONT>
  2105.     if (fonttag) {
  2106.         write(w, "</" + convertCase(Constants.FONT) + ">");
  2107.         inFont--;
  2108.     }
  2109.  
  2110.     // Close off b, i, or u.
  2111.         if (underlinetag)
  2112.             write(w, "</" + convertCase(u) + ">");
  2113.         if (italictag)
  2114.             write(w, "</" + convertCase(i) + ">");
  2115.         if (boldtag)
  2116.             write(w, "</" + convertCase(b) + ">");
  2117.  
  2118.     }
  2119.  
  2120.     /**
  2121.      * Writes out content for this element.
  2122.      * Strips off the extra \n added by the HTMLDocument reader
  2123.      * needed for the editing model.
  2124.      */
  2125.     private void writeText(Writer w, Element e) {
  2126.  
  2127.     try {
  2128.         StyledDocument doc = (StyledDocument)e.getDocument();
  2129.         String text = doc.getText(e.getStartOffset(),
  2130.                      e.getEndOffset() - e.getStartOffset());
  2131.         if (text.endsWith("\n")) {
  2132.             writeText(w, doc.getText(e.getStartOffset(),
  2133.                      e.getEndOffset() - e.getStartOffset()-1));
  2134.         }
  2135.         else
  2136.             writeText(w, doc.getText(e.getStartOffset(),
  2137.                      e.getEndOffset() - e.getStartOffset()));
  2138.     } catch (BadLocationException ex) {
  2139.         HTMLDebug.println("HTMLWriter.writeText:" + e);
  2140.     }
  2141.  
  2142.     }
  2143.  
  2144.     /**
  2145.      * Writes out content for this element.
  2146.      * Don't strip off the extra \n added by the HTMLDocument reader
  2147.      * needed for the editing model.
  2148.      */
  2149.     private void writePreText(Writer w, Element e) {
  2150.  
  2151.     if (writePre == true && nPrelines >= 0) {
  2152.  
  2153.         try {
  2154.             StyledDocument doc = (StyledDocument)e.getDocument();
  2155.             String text = doc.getText(e.getStartOffset(),
  2156.                      e.getEndOffset() - e.getStartOffset());
  2157.             //
  2158.             // If text is empty, then write a \n because
  2159.             // this was a blank line.
  2160.             //
  2161.             if (e.getStartOffset() == e.getEndOffset() && nPrelines > 0) {
  2162.                   writeChar(w, '\n');
  2163.             writePre = false;
  2164.             }
  2165.         else if (nPrelines == 0 && e.getEndOffset() - 1 > e.getStartOffset() &&
  2166.              doc.getText(e.getStartOffset(), e.getEndOffset() - e.getStartOffset()).endsWith("\n")) {
  2167.                 writeText(w, doc.getText(e.getStartOffset(),
  2168.                      e.getEndOffset() - e.getStartOffset() - 1));
  2169.             writePre = true;
  2170.         }
  2171.             else {
  2172.                 writeText(w, doc.getText(e.getStartOffset(),
  2173.                      e.getEndOffset() - e.getStartOffset()));
  2174.             writePre = true;
  2175.             }
  2176.         } catch (BadLocationException ex) {
  2177.             HTMLDebug.println("HTMLWriter.writeText:" + e);
  2178.         }
  2179.     }
  2180.             //writePre = false;
  2181.  
  2182.     }
  2183.  
  2184.     /**
  2185.      * Write a char out
  2186.      */
  2187.     public void writeChar(Writer w, char c) {
  2188.  
  2189.           HTMLDebug.println("Output=>" + c + "<=");
  2190.     try {
  2191.         switch (c) {
  2192.               case '<': w.write("<"); break;
  2193.           case '>': w.write(">"); break;
  2194.           case '&': w.write("&"); break;
  2195.           case '"': w.write("""); break;
  2196.  
  2197.           default:
  2198.             if ((c == '\n') || (c == '\t') || (c == '\r'))
  2199.             w.write(c);
  2200.                 else if ((c < ' ') || (c > 127)) {
  2201.             w.write("&#");
  2202.             w.write(String.valueOf((int)c));
  2203.             w.write(";");
  2204.                 } else {
  2205.             w.write(c);
  2206.             }
  2207.         }
  2208.     } 
  2209.     catch (IOException e) {
  2210.         System.out.println("HTMLWriter.write: " + c + " " +  e);
  2211.     }
  2212.     }
  2213.  
  2214.     private void writeText(Writer w, String data) {
  2215.     int len = data.length();
  2216.     for (int i = 0; i < len; i++) {
  2217.             writeChar(w, data.charAt(i));
  2218.      }
  2219.     }
  2220. }
  2221.  
  2222.